#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>

const int msgQueueKeyIn = 1600 ;
const int msgQueueKeyOut = 1601 ;
const int SPORT = 2000 ;
const int msgType = 100 ;
const int dataLen = 1024 ;
const int hostNameLen = 256 ;
const int maxTranBytes = 128 ;
const int netBufferLen = 256 ;


struct Message
{
    long msgType ;
    char data[dataLen] ;
} ;

int main ()
{
    Message msgIn, msgOut ;
    struct hostent * host ;
    struct sockaddr_in sn ;
    struct sockaddr sk ;
    int len = sizeof (sk) ;
	

	
    int sd, conn, flag, count, qcount ;
    char hostName[hostNameLen], netBuffer[netBufferLen] ;

    //Create message queue
	//IDs for in and out msg queues
	int inMsgQueueID, outMsgQueueID ;
    if ( (inMsgQueueID=msgget(msgQueueKeyIn, IPC_CREAT | 0660)) == -1 )
    {
        perror("inMsgQueueID error!");
        exit(1) ;
    }
    if ( (outMsgQueueID=msgget(msgQueueKeyOut, IPC_CREAT | 0660)) == -1 )
    {
        perror ( "outMsgQueueID error!" ) ;
        exit(1) ;
    }

    //Get local host name
    if ( (flag=gethostname(hostName, sizeof(hostName))) == -1 )
    {
        perror ( "gethostname error!" ) ;
        exit(1) ;
    }

    //Get local host address accroding its name
    if ( (host=gethostbyname(hostName) ) == NULL )
    {
        perror( "gethostbyname error!" ) ;
        exit(1) ;
    }
    bzero((char *)&sn, sizeof(sn)) ;

    //Set address family
    sn.sin_family = AF_INET ;
    //Chage host byte order of port into network byte order
    sn.sin_port = htons (SPORT) ;
    bcopy(host->h_addr, (char *)&sn.sin_addr, host->h_length ); 

    //Create socket. Use IP+TCP
    if( (sd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
    {
        close(sd) ;
        perror("socket error!") ;
        exit(1) ;
    }

    if (bind(sd, (struct sockaddr *)&sn, sizeof(sn)))
    {
        close(sd) ;
        perror("bind error!") ;
        exit(1) ;
    }

    //Client occupy connection privately, so set the queue length to be 1.
    if ( listen(sd, 1))
    {
        perror("listen error!") ;
        exit(1) ;
    }

    while(1)
    {
        if ((conn=accept(sd, (struct sockaddr *)(&sk), (socklen_t *)(&len))) == -1 )
        {
            close(sd) ;
            perror("accept error!") ;
            exit(1) ;
        }

        while(1) 
        {
            count = recv (conn, netBuffer, maxTranBytes, 0) ;
            if (count > 0)
            {
                msgIn.msgType = msgType ;
                bcopy ( netBuffer, msgIn.data, maxTranBytes) ;
                qcount = msgsnd ( inMsgQueueID, &msgIn, maxTranBytes , 0) ;
            }
            else if (count == 0)
                break;
            qcount = msgrcv ( outMsgQueueID, &msgOut, maxTranBytes, 0, 0 ) ;
            count = send ( conn, msgOut.data, maxTranBytes, 0 ) ;
        }
        close(conn) ;
    }
}


